package org.example.nebula.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.csv.*;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.Strings;
import org.example.nebula.entity.input.NgInsertEdgeInput;
import org.example.nebula.entity.input.NgInsertTagInput;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: jszhang
 * @date: 2024/10/25-11:54
 */
@Slf4j
@Service
public class ImportDataService {

    @Autowired
    private CommonService commonService;

    public void insertTagData(NgInsertTagInput ngInsertTagInput) {
        log.info(ngInsertTagInput.getCsvPath());

        String csvPath = ngInsertTagInput.getCsvPath();
        String spaceName = ngInsertTagInput.getSpaceName();
        String tagName = ngInsertTagInput.getTagName();
        List<String> keyList = new ArrayList<>();
        List<String> errorList = new ArrayList<>();
        boolean check = true;
        long lineNumber = 0;
        int batch = 1000;
        try {
            List<String> rows = FileUtil.readLines(csvPath, StandardCharsets.UTF_8);
            if (rows.size() > 1000000) {
                batch = 10000;
            }
            for (String row : rows) {
                if (check) {
                    String[] titleArray = row.split(",");
                    for (int i = 1; i < titleArray.length; i++) {
                        keyList.add(titleArray[i]);
                    }

                    check = false;
                } else {
                    String[] itemArray = row.split(",");

                    String prop = String.join(",", keyList);
                    StringBuilder sql = new StringBuilder();
                    sql.append("use " + spaceName + "; insert vertex " + tagName + "(" + prop + ") values ");
                    sql.append("'" + itemArray[0] + "':(");
                    for (int i = 1; i < itemArray.length; i++) {
                        if (i == itemArray.length - 1) {
                            sql.append("'" + itemArray[i].replace("'", "\\'").replaceAll("\n", " ") + "')");
                        } else {
                            sql.append("'" + itemArray[i].replace("'", "\\'").replaceAll("\n", " ") + "',");
                        }
                    }

//                        log.info(sql.toString());

                    try {
                        JSONArray jsonArray = commonService.executeJson(sql.toString());
                        int code = jsonArray.getJSONObject(0).getJSONObject("errors").getInt("code");
                        if (code != 0) {
                            errorList.add(row);
                        }
                    } catch (Exception e) {
                        errorList.add(row);
                    }
                }

                lineNumber++;
                if (lineNumber % batch == 0) {
                    log.info("共计{}行，已导入{}行", rows.size(), lineNumber);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("共导入{}行", lineNumber);

        if (CollectionUtil.isNotEmpty(errorList)) {
            try {

                String errorPath = "F:\\NebulaGraph\\sx_kg/error" + tagName + "_node_error.csv";
                //指定路径和编码
                CsvWriter writer = CsvUtil.getWriter(errorPath, CharsetUtil.CHARSET_UTF_8);
                writer.write(errorList);
                writer.flush();
                writer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void insertEdgeData(NgInsertEdgeInput ngInsertEdgeInput) {
        String csvPath = ngInsertEdgeInput.getCsvPath();
        String spaceName = ngInsertEdgeInput.getSpaceName();
        String edgeName = ngInsertEdgeInput.getEdgeName();

        List<String> keyList = new ArrayList<>();
        List<String[]> errorList = new ArrayList<>();
        long lineNumber = 0;
        boolean check = true;
        try {
            CSVReader csvReader = new CSVReader(new FileReader(csvPath));
            while (true) {
                String[] strings = csvReader.readNext();
                if (strings != null) {
                    if (check) {
                        for (int i = 2; i < strings.length; i++) {
                            keyList.add(strings[i]);
                        }

                        check = false;
                    } else {
                        StringBuilder sql = new StringBuilder();
                        if (CollUtil.isEmpty(keyList)) {
                            sql.append("use " + spaceName + "; insert edge " + edgeName + "() values ");
                            sql.append("'" + strings[0] + "'->'" + strings[1] + "'@1:()");
                        } else {
                            String prop = String.join(",", keyList);
                            sql.append("use " + spaceName + "; insert edge " + edgeName + "("  + prop +  ") values ");
                            sql.append("'" + strings[0] + "'->'" + strings[1] + "'@1:(");
                            for (int i = 2; i < strings.length; i++) {
                                if (i == strings.length - 1) {
                                    sql.append("'" + strings[i].replace("'", "\\'") + "')");
                                } else {
                                    sql.append("'" + strings[i].replace("'", "\\'") + "',");
                                }
                            }
                        }

//                        log.info(sql.toString());
                        try {
                            JSONArray jsonArray = commonService.executeJson(sql.toString());
                            int code = jsonArray.getJSONObject(0).getJSONObject("errors").getInt("code");
                            if (code != 0) {
                                errorList.add(strings);
                            }
                        } catch (Exception e) {
                            errorList.add(strings);
                        }
                    }
                } else {
                    break;
                }

                lineNumber++;
                if (lineNumber % 1000 == 0) {
                    log.info("已导入{}行", lineNumber);
                }
            }
            log.info("共导入{}行", lineNumber);

            if (CollectionUtil.isNotEmpty(errorList)) {
                try {
                    FileOutputStream fileOutputStream = new FileOutputStream("F:/data/error/" + edgeName + "_error.csv");
                    CSVWriter csvWriter = new CSVWriter(new OutputStreamWriter(fileOutputStream));
                    for (int i = 0; i < errorList.size(); i++) {
                        csvWriter.writeNext(errorList.get(i));
                    }
                    csvWriter.flush();
                    csvWriter.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }

    }

    public void insertEdgeDataWithNoRank(NgInsertEdgeInput ngInsertEdgeInput) {
        String csvPath = ngInsertEdgeInput.getCsvPath();
        String spaceName = ngInsertEdgeInput.getSpaceName();
        String edgeName = ngInsertEdgeInput.getEdgeName();

        List<String> keyList = new ArrayList<>();
        List<String> errorList = new ArrayList<>();
        long lineNumber = 0;
        boolean check = true;
        int batch = 1000;
        try {
            List<String> rows = FileUtil.readLines(csvPath, StandardCharsets.UTF_8);
            if (rows.size() > 1000000) {
                batch = 10000;
            }
            for (String lineInfo : rows) {
                String[] titleArray = lineInfo.split("->");
                if (check) {
                    for (int i = 2; i < titleArray.length; i++) {
                        keyList.add(titleArray[i]);
                    }
                    check = false;
                } else {
                    String[] itemArray = lineInfo.split("->");

                    StringBuilder sql = new StringBuilder();
                    if (CollUtil.isEmpty(keyList)) {
                        sql.append("use " + spaceName + "; insert edge " + edgeName + "() values ");
                        sql.append("'" + itemArray[0] + "'->'" + itemArray[1] + "'@0:()");
                    } else {
                        String prop = String.join(",", keyList);
                        sql.append("use " + spaceName + "; insert edge " + edgeName + "("  + prop +  ") values ");
                        sql.append("'" + itemArray[0] + "'->'" + itemArray[1] + "'@0:(");
                        for (int i = 2; i < itemArray.length; i++) {
                            if (i == itemArray.length - 1) {
                                sql.append("'" + itemArray[i].replace("'", "\\'") + "')");
                            } else {
                                sql.append("'" + itemArray[i].replace("'", "\\'") + "',");
                            }
                        }
                    }

//                        log.info(sql.toString());
                    try {
                        JSONArray jsonArray = commonService.executeJson(sql.toString());
                        int code = jsonArray.getJSONObject(0).getJSONObject("errors").getInt("code");
                        if (code != 0) {
                            errorList.add(lineInfo);
                        }
                    } catch (Exception e) {
                        errorList.add(lineInfo);
                    }
                }

                lineNumber++;
                if (lineNumber % batch == 0) {
                    log.info("共计{}行，已导入{}行", rows.size(), lineNumber);
                }
            }
            log.info("共导入{}行", lineNumber);

            if (CollectionUtil.isNotEmpty(errorList)) {
                try {
                    String errorPath = "F:\\NebulaGraph/sx_kg/error/" + edgeName + "_error.csv";
                    //指定路径和编码
                    CsvWriter writer = CsvUtil.getWriter(errorPath, CharsetUtil.CHARSET_UTF_8);
                    writer.write(errorList);
                    writer.flush();
                    writer.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }

    }

}
